{
 "nbformat": 4,
 "nbformat_minor": 0,
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  },
  "accelerator": "GPU",
  "gpuClass": "standard"
 },
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "\n",
    "**Best-of-n sampling as an alternative to RLHF**\n",
    "\n",
    "This notebook compares reward-model scores of prompt based responses from \n",
    "1. a base model (`gpt2-imdb`)\n",
    "2. `RLHF` tuned model based on this base-model \n",
    "3. the base-model again from which we sample n responses to each prompt, score them and take the best scored one AKA the `best-of-n sampled` model\n",
    "\n"
   ],
   "metadata": {
    "id": "WQpNapZNWuXP"
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Import dependencies\n"
   ],
   "metadata": {
    "id": "Lo98lkdP66_x"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "%pip install transformers trl"
   ],
   "metadata": {
    "id": "vDA6qayz692w"
   },
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "import torch\n",
    "import pandas as pd\n",
    "from transformers import pipeline, AutoTokenizer\n",
    "from datasets import load_dataset\n",
    "\n",
    "from trl import AutoModelForCausalLMWithValueHead\n",
    "from trl.core import LengthSampler\n",
    "\n",
    "device = 0 if torch.cuda.is_available() else \"cpu\""
   ],
   "metadata": {
    "id": "M1s_iNm773hM"
   },
   "execution_count": 2,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "Various constants"
   ],
   "metadata": {
    "id": "Y7hyrIrO8tcY"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "ref_model_name = \"lvwerra/gpt2-imdb\"\n",
    "model_name = \"lvwerra/gpt2-imdb-pos-v2\"\n",
    "reward_model = \"lvwerra/distilbert-imdb\"\n",
    "\n",
    "N_BEST_OF = 4"
   ],
   "metadata": {
    "id": "MqS3OM6Q8x6g"
   },
   "execution_count": 3,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "Models and  tokenizers "
   ],
   "metadata": {
    "id": "c1YcXeElg6or"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "model = AutoModelForCausalLMWithValueHead.from_pretrained(model_name)\n",
    "\n",
    "ref_model = AutoModelForCausalLMWithValueHead.from_pretrained(ref_model_name)\n",
    "\n",
    "reward_pipe = pipeline(\"sentiment-analysis\", model=reward_model, device=device)\n",
    "\n",
    "tokenizer = AutoTokenizer.from_pretrained(ref_model_name)\n",
    "\n",
    "tokenizer.pad_token = tokenizer.eos_token\n",
    "\n",
    "# cuda-ize models\n",
    "model.cuda()\n",
    "ref_model.cuda()"
   ],
   "metadata": {
    "id": "b855NrL181Hh"
   },
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "Dataset building"
   ],
   "metadata": {
    "id": "Z1Cz0gCFhZYJ"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "def build_dataset(tokenizer, dataset_name=\"imdb\", input_min_text_length=2, input_max_text_length=8):\n",
    "    # load imdb with datasets\n",
    "    ds = load_dataset(dataset_name, split=\"train\")\n",
    "    ds = ds.rename_columns({\"text\": \"review\"})\n",
    "    ds = ds.filter(lambda x: len(x[\"review\"]) > 200, batched=False)\n",
    "\n",
    "    input_size = LengthSampler(input_min_text_length, input_max_text_length)\n",
    "\n",
    "    def tokenize(sample):\n",
    "        sample[\"input_ids\"] = tokenizer.encode(sample[\"review\"])[: input_size()]\n",
    "        sample[\"query\"] = tokenizer.decode(sample[\"input_ids\"])\n",
    "        return sample\n",
    "\n",
    "    ds = ds.map(tokenize, batched=False)\n",
    "    ds.set_format(type=\"torch\")\n",
    "    return ds\n",
    "\n",
    "\n",
    "dataset = build_dataset(tokenizer)"
   ],
   "metadata": {
    "id": "LqLVEp5p_8XM"
   },
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "gen_kwargs = {\"min_length\": -1, \"top_k\": 0.0, \"top_p\": 1.0, \"do_sample\": True, \"pad_token_id\": tokenizer.eos_token_id}\n",
    "sent_kwargs = {\"top_k\": None, \"function_to_apply\": \"none\", \"batch_size\": 16}"
   ],
   "metadata": {
    "id": "AqA2McjMAxNw"
   },
   "execution_count": 6,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "output_min_length = 4\n",
    "output_max_length = 16\n",
    "output_length_sampler = LengthSampler(output_min_length, output_max_length)\n",
    "\n",
    "#### get a batch from the dataset\n",
    "bs = 16\n",
    "output_data = dict()\n",
    "dataset.set_format(\"pandas\")\n",
    "df_batch = dataset[:].sample(bs)\n",
    "output_data[\"query\"] = df_batch[\"query\"].tolist()\n",
    "query_tensors = df_batch[\"input_ids\"].tolist()\n",
    "\n",
    "# :: [Resp]\n",
    "response_tensors_ref, response_tensors = [], []\n",
    "# :: [[Resp]]\n",
    "response_tensors_best_of = []"
   ],
   "metadata": {
    "id": "L_q4qs35AxcR"
   },
   "execution_count": 7,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "\n",
    "Generation using various models"
   ],
   "metadata": {
    "id": "QVfpyHnZBLKY"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "for i in range(bs):\n",
    "    gen_len = output_length_sampler()\n",
    "\n",
    "    query = torch.tensor(query_tensors[i])\n",
    "\n",
    "    output = ref_model.generate(query.unsqueeze(dim=0).to(device), max_new_tokens=gen_len, **gen_kwargs).squeeze()\n",
    "    response_tensors_ref.append(tokenizer.decode(output))\n",
    "\n",
    "    output = model.generate(query.unsqueeze(dim=0).to(device), max_new_tokens=gen_len, **gen_kwargs).squeeze()\n",
    "    response_tensors.append(tokenizer.decode(output))\n",
    "\n",
    "    # generating copies of the same query for the Best-of-n sampling\n",
    "    queries = query.repeat((N_BEST_OF, 1))\n",
    "    output = ref_model.generate(queries.to(device), max_new_tokens=gen_len, **gen_kwargs).squeeze()\n",
    "    response_tensors_best_of.append(tokenizer.batch_decode(output))"
   ],
   "metadata": {
    "id": "-imZ7uEFBNbw"
   },
   "execution_count": 8,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "Scoring"
   ],
   "metadata": {
    "id": "Jp5FC0Y5h_Sf"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "scores_ref = [output[0][\"score\"] for output in reward_pipe(response_tensors_ref, **sent_kwargs)]\n",
    "scores = [output[0][\"score\"] for output in reward_pipe(response_tensors, **sent_kwargs)]\n",
    "scores_best_of = []\n",
    "for i, response in enumerate(response_tensors_best_of):\n",
    "    # base_score = scores_ref[i]\n",
    "    scores_best_of.append(torch.tensor([output[0][\"score\"] for output in reward_pipe(response, **sent_kwargs)]))"
   ],
   "metadata": {
    "id": "PyDbbAQ0F_h7"
   },
   "execution_count": null,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "output_data[\"response (ref)\"] = response_tensors_ref\n",
    "output_data[\"scores (ref)\"] = scores_ref\n",
    "output_data[\"response (RLHF)\"] = response_tensors\n",
    "output_data[\"scores (RLHF)\"] = scores\n",
    "output_data[\"response (best_of)\"] = [\n",
    "    response_tensors_best_of[i][a.argmax().item()] for i, a in enumerate(scores_best_of)\n",
    "]\n",
    "output_data[\"scores (best_of)\"] = [a.max().item() for a in scores_best_of]\n",
    "\n",
    "\n",
    "# store results in a dataframe\n",
    "df_results = pd.DataFrame(output_data)\n",
    "df_results"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 682
    },
    "id": "nA1GDNJEiGm-",
    "outputId": "1389c686-0751-4304-dea2-b71fd68748e1"
   },
   "execution_count": 10,
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": [
       "                                 query  \\\n",
       "0                     I'm a pretty old   \n",
       "1                      One of the most   \n",
       "2                             Okay, as   \n",
       "3                        Watching \"Kro   \n",
       "4   Seriously what were they thinking?   \n",
       "5                         OK Hollywood   \n",
       "6                             \"Bend It   \n",
       "7   While the premise behind The House   \n",
       "8                       Well let me go   \n",
       "9                Vijay Krishna Acharya   \n",
       "10         Watching this movie made me   \n",
       "11                  There are probably   \n",
       "12                          Meryl Stre   \n",
       "13     I thought I read somewhere that   \n",
       "14                    Good movie, very   \n",
       "15                    It was agonizing   \n",
       "\n",
       "                                       response (ref)  scores (ref)  \\\n",
       "0       I'm a pretty old kid, well, with lots of girl      1.179652   \n",
       "1   One of the most psychologically devastating as...      2.477277   \n",
       "2   Okay, as ruthless as they are, even their leve...      1.466462   \n",
       "3                            Watching \"Kroger\" (1915-      0.186047   \n",
       "4   Seriously what were they thinking? It ain't go...      1.010697   \n",
       "5   OK Hollywood goes into a total game of audio, ...      0.934041   \n",
       "6   \"Bend It, Luther, Dodge, Church Goes to Rome w...      0.039218   \n",
       "7   While the premise behind The House of Dracula ...     -0.079306   \n",
       "8   Well let me go...I don't want to movie it. I'm...      1.015246   \n",
       "9    Vijay Krishna Acharya Sawai (Elverling). She was      0.341506   \n",
       "10  Watching this movie made me poorly appreciate ...      1.574047   \n",
       "11  There are probably more but if you had never s...     -0.047099   \n",
       "12                          Meryl Streep's version of      0.373884   \n",
       "13  I thought I read somewhere that the Lord had c...      0.091776   \n",
       "14  Good movie, very funny, acting is very good.<|...      2.408837   \n",
       "15            It was agonizing, and it made me wonder      1.240262   \n",
       "\n",
       "                                      response (RLHF)  scores (RLHF)  \\\n",
       "0   I'm a pretty old lady, and I loved this movie ...       2.218363   \n",
       "1      One of the most Antibiotic Apps I have seen in       2.145479   \n",
       "2   Okay, as I enjoyed the movie. It's added bonus...       2.239827   \n",
       "3                   Watching \"Kroven\". The film has a       1.044690   \n",
       "4   Seriously what were they thinking? It's a very...       2.753088   \n",
       "5   OK Hollywood shoot, and this is a classic. Som...       2.517364   \n",
       "6   \"Bend It all\" is a sophisticated, drawing and ...       2.583935   \n",
       "7   While the premise behind The House Intelligenc...       0.205217   \n",
       "8   Well let me go through everything says it's a ...       2.727040   \n",
       "9   Vijay Krishna Acharya is a perfect performance...       2.563642   \n",
       "10  Watching this movie made me sleep better. It w...       1.690222   \n",
       "11  There are probably random man only recently wh...       0.398258   \n",
       "12                              Meryl Streitz, who is       0.085154   \n",
       "13  I thought I read somewhere that my thoughts, a...       1.833734   \n",
       "14  Good movie, very much fuzz and logical based w...       2.325996   \n",
       "15       It was agonizing because it was truly fun to       0.969669   \n",
       "\n",
       "                                   response (best_of)  scores (best_of)  \n",
       "0   I'm a pretty old, stinking,acting kinda chick ...          2.016955  \n",
       "1   One of the most memorable performances of this...          2.676944  \n",
       "2   Okay, as I put it in such a negative mood, it ...          1.478424  \n",
       "3            Watching \"Kro\" is an entertainment craze          1.389495  \n",
       "4   Seriously what were they thinking? It was stil...          2.523514  \n",
       "5   OK Hollywood pay and the freaky set-up of this...          1.634765  \n",
       "6   \"Bend It 9\"/\"Zara Pephoto\") and an honest, rea...          2.557210  \n",
       "7   While the premise behind The House of Dracula ...          1.676889  \n",
       "8   Well let me go though, alive in this ever grow...          2.652859  \n",
       "9   Vijay Krishna Acharya adeptly emerges, and the...          2.308076  \n",
       "10  Watching this movie made me curious: what did ...          0.950836  \n",
       "11  There are probably too many documentaries in s...          1.142725  \n",
       "12                      Meryl Streep performed an awe          1.932498  \n",
       "13  I thought I read somewhere that The Odd Couple...          0.475951  \n",
       "14  Good movie, very well polished, nicely written...          2.820022  \n",
       "15           It was agonizing, poignant, and worst of          2.058277  "
      ],
      "text/html": [
       "\n",
       "  <div id=\"df-f55eb9dc-030e-4d67-8f1c-6f797f325376\">\n",
       "    <div class=\"colab-df-container\">\n",
       "      <div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>query</th>\n",
       "      <th>response (ref)</th>\n",
       "      <th>scores (ref)</th>\n",
       "      <th>response (RLHF)</th>\n",
       "      <th>scores (RLHF)</th>\n",
       "      <th>response (best_of)</th>\n",
       "      <th>scores (best_of)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>I'm a pretty old</td>\n",
       "      <td>I'm a pretty old kid, well, with lots of girl</td>\n",
       "      <td>1.179652</td>\n",
       "      <td>I'm a pretty old lady, and I loved this movie ...</td>\n",
       "      <td>2.218363</td>\n",
       "      <td>I'm a pretty old, stinking,acting kinda chick ...</td>\n",
       "      <td>2.016955</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>One of the most</td>\n",
       "      <td>One of the most psychologically devastating as...</td>\n",
       "      <td>2.477277</td>\n",
       "      <td>One of the most Antibiotic Apps I have seen in</td>\n",
       "      <td>2.145479</td>\n",
       "      <td>One of the most memorable performances of this...</td>\n",
       "      <td>2.676944</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Okay, as</td>\n",
       "      <td>Okay, as ruthless as they are, even their leve...</td>\n",
       "      <td>1.466462</td>\n",
       "      <td>Okay, as I enjoyed the movie. It's added bonus...</td>\n",
       "      <td>2.239827</td>\n",
       "      <td>Okay, as I put it in such a negative mood, it ...</td>\n",
       "      <td>1.478424</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Watching \"Kro</td>\n",
       "      <td>Watching \"Kroger\" (1915-</td>\n",
       "      <td>0.186047</td>\n",
       "      <td>Watching \"Kroven\". The film has a</td>\n",
       "      <td>1.044690</td>\n",
       "      <td>Watching \"Kro\" is an entertainment craze</td>\n",
       "      <td>1.389495</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Seriously what were they thinking?</td>\n",
       "      <td>Seriously what were they thinking? It ain't go...</td>\n",
       "      <td>1.010697</td>\n",
       "      <td>Seriously what were they thinking? It's a very...</td>\n",
       "      <td>2.753088</td>\n",
       "      <td>Seriously what were they thinking? It was stil...</td>\n",
       "      <td>2.523514</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>OK Hollywood</td>\n",
       "      <td>OK Hollywood goes into a total game of audio, ...</td>\n",
       "      <td>0.934041</td>\n",
       "      <td>OK Hollywood shoot, and this is a classic. Som...</td>\n",
       "      <td>2.517364</td>\n",
       "      <td>OK Hollywood pay and the freaky set-up of this...</td>\n",
       "      <td>1.634765</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>\"Bend It</td>\n",
       "      <td>\"Bend It, Luther, Dodge, Church Goes to Rome w...</td>\n",
       "      <td>0.039218</td>\n",
       "      <td>\"Bend It all\" is a sophisticated, drawing and ...</td>\n",
       "      <td>2.583935</td>\n",
       "      <td>\"Bend It 9\"/\"Zara Pephoto\") and an honest, rea...</td>\n",
       "      <td>2.557210</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>While the premise behind The House</td>\n",
       "      <td>While the premise behind The House of Dracula ...</td>\n",
       "      <td>-0.079306</td>\n",
       "      <td>While the premise behind The House Intelligenc...</td>\n",
       "      <td>0.205217</td>\n",
       "      <td>While the premise behind The House of Dracula ...</td>\n",
       "      <td>1.676889</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>Well let me go</td>\n",
       "      <td>Well let me go...I don't want to movie it. I'm...</td>\n",
       "      <td>1.015246</td>\n",
       "      <td>Well let me go through everything says it's a ...</td>\n",
       "      <td>2.727040</td>\n",
       "      <td>Well let me go though, alive in this ever grow...</td>\n",
       "      <td>2.652859</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Vijay Krishna Acharya</td>\n",
       "      <td>Vijay Krishna Acharya Sawai (Elverling). She was</td>\n",
       "      <td>0.341506</td>\n",
       "      <td>Vijay Krishna Acharya is a perfect performance...</td>\n",
       "      <td>2.563642</td>\n",
       "      <td>Vijay Krishna Acharya adeptly emerges, and the...</td>\n",
       "      <td>2.308076</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>Watching this movie made me</td>\n",
       "      <td>Watching this movie made me poorly appreciate ...</td>\n",
       "      <td>1.574047</td>\n",
       "      <td>Watching this movie made me sleep better. It w...</td>\n",
       "      <td>1.690222</td>\n",
       "      <td>Watching this movie made me curious: what did ...</td>\n",
       "      <td>0.950836</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>There are probably</td>\n",
       "      <td>There are probably more but if you had never s...</td>\n",
       "      <td>-0.047099</td>\n",
       "      <td>There are probably random man only recently wh...</td>\n",
       "      <td>0.398258</td>\n",
       "      <td>There are probably too many documentaries in s...</td>\n",
       "      <td>1.142725</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>Meryl Stre</td>\n",
       "      <td>Meryl Streep's version of</td>\n",
       "      <td>0.373884</td>\n",
       "      <td>Meryl Streitz, who is</td>\n",
       "      <td>0.085154</td>\n",
       "      <td>Meryl Streep performed an awe</td>\n",
       "      <td>1.932498</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>I thought I read somewhere that</td>\n",
       "      <td>I thought I read somewhere that the Lord had c...</td>\n",
       "      <td>0.091776</td>\n",
       "      <td>I thought I read somewhere that my thoughts, a...</td>\n",
       "      <td>1.833734</td>\n",
       "      <td>I thought I read somewhere that The Odd Couple...</td>\n",
       "      <td>0.475951</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>Good movie, very</td>\n",
       "      <td>Good movie, very funny, acting is very good.&lt;|...</td>\n",
       "      <td>2.408837</td>\n",
       "      <td>Good movie, very much fuzz and logical based w...</td>\n",
       "      <td>2.325996</td>\n",
       "      <td>Good movie, very well polished, nicely written...</td>\n",
       "      <td>2.820022</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>It was agonizing</td>\n",
       "      <td>It was agonizing, and it made me wonder</td>\n",
       "      <td>1.240262</td>\n",
       "      <td>It was agonizing because it was truly fun to</td>\n",
       "      <td>0.969669</td>\n",
       "      <td>It was agonizing, poignant, and worst of</td>\n",
       "      <td>2.058277</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>\n",
       "      <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-f55eb9dc-030e-4d67-8f1c-6f797f325376')\"\n",
       "              title=\"Convert this dataframe to an interactive table.\"\n",
       "              style=\"display:none;\">\n",
       "        \n",
       "  <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n",
       "       width=\"24px\">\n",
       "    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n",
       "    <path d=\"M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z\"/><path d=\"M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z\"/>\n",
       "  </svg>\n",
       "      </button>\n",
       "      \n",
       "  <style>\n",
       "    .colab-df-container {\n",
       "      display:flex;\n",
       "      flex-wrap:wrap;\n",
       "      gap: 12px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert {\n",
       "      background-color: #E8F0FE;\n",
       "      border: none;\n",
       "      border-radius: 50%;\n",
       "      cursor: pointer;\n",
       "      display: none;\n",
       "      fill: #1967D2;\n",
       "      height: 32px;\n",
       "      padding: 0 0 0 0;\n",
       "      width: 32px;\n",
       "    }\n",
       "\n",
       "    .colab-df-convert:hover {\n",
       "      background-color: #E2EBFA;\n",
       "      box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
       "      fill: #174EA6;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert {\n",
       "      background-color: #3B4455;\n",
       "      fill: #D2E3FC;\n",
       "    }\n",
       "\n",
       "    [theme=dark] .colab-df-convert:hover {\n",
       "      background-color: #434B5C;\n",
       "      box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
       "      filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
       "      fill: #FFFFFF;\n",
       "    }\n",
       "  </style>\n",
       "\n",
       "      <script>\n",
       "        const buttonEl =\n",
       "          document.querySelector('#df-f55eb9dc-030e-4d67-8f1c-6f797f325376 button.colab-df-convert');\n",
       "        buttonEl.style.display =\n",
       "          google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
       "\n",
       "        async function convertToInteractive(key) {\n",
       "          const element = document.querySelector('#df-f55eb9dc-030e-4d67-8f1c-6f797f325376');\n",
       "          const dataTable =\n",
       "            await google.colab.kernel.invokeFunction('convertToInteractive',\n",
       "                                                     [key], {});\n",
       "          if (!dataTable) return;\n",
       "\n",
       "          const docLinkHtml = 'Like what you see? Visit the ' +\n",
       "            '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
       "            + ' to learn more about interactive tables.';\n",
       "          element.innerHTML = '';\n",
       "          dataTable['output_type'] = 'display_data';\n",
       "          await google.colab.output.renderOutput(dataTable, element);\n",
       "          const docLink = document.createElement('div');\n",
       "          docLink.innerHTML = docLinkHtml;\n",
       "          element.appendChild(docLink);\n",
       "        }\n",
       "      </script>\n",
       "    </div>\n",
       "  </div>\n",
       "  "
      ]
     },
     "metadata": {},
     "execution_count": 10
    }
   ]
  }
 ]
}